package apisync

import (
	"os"
	"bufio"
	"io"
	"strings"
	"fmt"
	"os/exec"
)

type RunIn struct {
	Root string
	Dir string
	File string
}
func Run(in *RunIn) {
	//获取route
	routes := parseRoute(in.File)
	if len(routes) == 0 {
		fmt.Println("无配置路由")
		return
	}

	var err error

	//写入api
	err = writeApi(in.Dir, routes)
	if err != nil {
		panic(err)
	}

	//写入无需权限路由
	err = writrNoAuth(in.Dir+"/route", routes)
	if err != nil {
		panic(err)
	}

	//写入路由
	err = writeRoute(in.Root, in.Dir, routes)
	if err != nil {
		panic(err)
	}

	fmt.Println("同步完成")
}

func writeApi(dir string,routes []Route) error {
	for _,r := range routes {
		tmpDir := dir+"/"+r.Version+"/"+r.Module
		if _,err := os.Stat(tmpDir);err != nil {
			os.MkdirAll(tmpDir,0666)
		}
		//判断基础文件是否存在
		moduleTitle := strings.Title(r.Module)
		baseFile := tmpDir+"/"+r.Module+".go"
		_,err := os.Stat(baseFile)

		if err != nil {
			//写入文件
			content := ""
			content += "package "+r.Module+" \n\n"
			content += "type "+moduleTitle+"Api struct {} \n\n"
			content += "func New"+moduleTitle+"Api() *"+moduleTitle+"Api { \n"
			content += "return new("+moduleTitle+"Api) \n"
			content += "} \n\n"
			bf,err := os.OpenFile(baseFile,os.O_CREATE|os.O_RDWR|os.O_TRUNC,0666)
			if err != nil {
				return err
			}
			bf.WriteString(content)
			bf.Close()
			cmd := exec.Command("gofmt","-w",baseFile)
			cmd.Run()
			fmt.Println(baseFile)
		}
		//写入接口
		apiFile := tmpDir+"/"+upperToUnder(r.Name)+".go"
		if _,err := os.Stat(apiFile);err != nil {
			var content string
			methodTitle := strings.Title(r.Name)
			methodName := moduleTitle+methodTitle
			content += "package "+r.Module+" \n\n"
			content += "import \"github.com/gin-gonic/gin\" \n\n"
			content += "type "+methodName+"In struct {} \n"
			content += "type "+methodName+"Out struct {} \n"
			content += "// @Summary "+r.Remark+" \n "+
			"// @Description "+r.Remark+" \n"+
			"// @Accept  json \n"+
			"// @Produce  json \n"
			if !r.NoAuth {
				content += "// @Param Authorization header string true \"token\" \n"
			}
			content += "// @Param body body "+methodName+"In true \"body\" \n"+
			"// @Success 200 {object} "+methodName+"Out \n"+
			"// @Router "+r.Uri+" ["+r.Method+"] \n"+
			"// @Tags "+r.Version+"-"+r.Module+" \n"
			content += "func ("+r.Module+"api *"+moduleTitle+"Api)"+methodTitle+"(ctx *gin.Context) { \n"
			content += "}\n\n"

			af,err := os.OpenFile(apiFile,os.O_CREATE|os.O_RDWR|os.O_TRUNC,0666)
			if err != nil {
				return err
			}
			af.WriteString(content)
			af.Close()
			cmd := exec.Command("gofmt","-w",apiFile)
			cmd.Run()
		}

	}
	return nil
}

func writrNoAuth(dir string, routes []Route) error {
	//判断目录是否存在
	if _,err := os.Stat(dir);err != nil {
		os.MkdirAll(dir,0666)
	}

	content := ""
	content += "package route \n\n"
	content += "func NoAuthUri() []string {\n"
	content += "return []string{ \n"
	for _,r := range routes {
		if r.NoAuth {
			content += "\""+r.Uri+"\",\n"
		}
	}
	content += "}\n"
	content += "}\n\n"

	filename := dir+"/no_auth.go"
	f,err := os.OpenFile(filename,os.O_CREATE|os.O_RDWR|os.O_TRUNC,0666)
	if err != nil {
		return err
	}
	f.WriteString(content)
	f.Close()

	cmd := exec.Command("gofmt","-w",filename)
	cmd.Run()
	return nil
}

func writeRoute(root,dir string, routes []Route) error {
	//文件分组
	cMap := make(map[string][]Route)

	for _,r := range routes {
		cMap[r.Version] = append(cMap[r.Version],r)
	}


	apiDir := root+"/"+dir
	//开始处理
	for k,rs := range cMap {
		modules := map[string]bool{
			"github.com/gin-gonic/gin": true,
		}

		var apiContent string
		for _,r := range rs {
			curModule := apiDir+"/"+r.Version+"/"+r.Module
			modules[curModule] = true

			apiContent += "//"+r.Remark+" \n"
			apiContent += "r.POST(\""+r.Uri+"\","+r.Module+".New"+strings.Title(r.Module)+"Api()."+strings.Title(r.Name)+") \n\n"
		}

		var content string
		content += "package route \n\n"
		content += "import ( \n"
		for m,_ := range modules {
			content += "\""+m+"\"\n"
		}
		content += ")\n\n"
		content += "func Set"+k+"(r *gin.Engine) { \n"
		content += apiContent
		content += "}\n"

		filename := dir+"/route/"+k+".go"
		f,err := os.OpenFile(filename,os.O_CREATE|os.O_RDWR|os.O_TRUNC,0666)
		if err != nil {
			return err
		}
		f.WriteString(content)
		f.Close()
		cmd := exec.Command("gofmt","-w",filename)
		cmd.Run()
	}

	return nil
}

type Route struct {
	Version string `json:"version"`
	Module string `json:"module"`
	Name string `json:"name"`
	Method string `json:"method"`
	Remark string `json:"remark"`
	NoAuth bool `json:"noAuth"`
	Uri string `json:"uri"`
}
func parseRoute(filename string) []Route {
	//读取文件
	file,err := os.Open(filename)
	if err != nil {
		panic(err)

	}
	defer file.Close()

	var routes []Route

	br := bufio.NewReader(file)
	for {
		line,_,err := br.ReadLine()
		if err != nil {
			if err == io.EOF {
				break
			}
			panic(err)
		}

		var route Route
		bysArr := strings.Split(string(line),"@")
		bysArrLen := len(bysArr)
		if bysArrLen < 5 {
			continue
		}
		//开始逐个解析
		route.Version = bysArr[0]
		route.Module = bysArr[1]
		route.Name = bysArr[2]
		route.Method = bysArr[3]
		route.Remark = bysArr[4]
		if bysArrLen==6 && bysArr[5] == "true" {
			route.NoAuth = true
		}
		route.Uri = fmt.Sprintf("/%s/%s/%s",route.Version,route.Module,upperToSlash(route.Name))
		routes = append(routes,route)
	}
	return routes
}

//大写的字母转斜杠
func upperToSlash(s string) string {
	var res []byte
	sLen := len(s)
	for i:=0;i<sLen;i++ {
		if i>0 && s[i] >= 'A' && s[i] <= 'Z' {
			res = append(res,'/',s[i]+32)
		} else {
			res = append(res,s[i])
		}
	}
	return string(res)
}

//大写字母转写划线
func upperToUnder(s string) string {
	var res []byte
	sLen := len(s)
	for i:=0;i<sLen;i++ {
		if i>0 && s[i] >= 'A' && s[i] <= 'Z' {
			res = append(res,'_',s[i]+32)
		} else {
			res = append(res,s[i])
		}
	}
	return string(res)
}

